﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AdvancedCollections.TreeHelper
{
    /// <summary>
    /// The class only moves to the right, MoveUp is automatically in case it can't move to the right
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class BinaryTreeEnumerator<T> : IEnumerator<T>
    {
        private Movment _nextMove = Movment.Up;

        private Stack<BinaryTreeNode<T>> _nodeHierarchy = new Stack<BinaryTreeNode<T>>();

        private BinaryTreeNode<T> _root;

        internal BinaryTreeEnumerator(BinaryTreeNode<T> root)
        {
            _root = root;
            ExpandNode(_root);
        }

        private enum Movment { Up, Right };

        public T Current
        {
            get { return _nodeHierarchy.Peek().Data; }
        }

        object IEnumerator.Current
        {
            get { return Current; }
        }

        public void Dispose()
        {
            _nodeHierarchy.Clear();
            _nodeHierarchy = null;
            _root = null;
        }

        public bool MoveNext()
        {
            if (_nextMove == Movment.Up)
                return MoveUp();
            else
                return MoveRight();
        }

        public void Reset()
        {
            _nodeHierarchy.Clear();
            ExpandNode(_root);
        }

        private void ExpandNode(BinaryTreeNode<T> currentNode)
        {
            while (!currentNode.IsEmpty)
            {
                _nodeHierarchy.Push(currentNode);
                currentNode = currentNode.LeftChild;
            }
        }

        private bool MoveRight()
        {
            if (_nodeHierarchy.Count == 0)
                return false;

            var currentNode = _nodeHierarchy.Pop();

            if (currentNode.RightChild.IsEmpty)
            {
                return MoveUp();
            }
            else
            {
                ExpandNode(currentNode.RightChild);
                return true;
            }
        }

        private bool MoveUp()
        {
            if (_nodeHierarchy.Count > 0)
            {
                _nextMove = Movment.Right;
                return true;
            }
            else
                return MoveRight();
        }
    }
}